<template>
	<view class="cpk-chart-container">
		<canvas class="cpk-chart" canvas-id="cpkChart" @touchstart="handleTouchStart" @touchmove="handleTouchMove"
			@touchend="handleTouchEnd"></canvas>
		<view class="chart-info">
			<view class="info-item">
				<text class="label">CPK值:</text>
				<text class="value">{{ cpkValue.toFixed(3) }}</text>
			</view>
			<view class="info-item">
				<text class="label">CP值:</text>
				<text class="value">{{ cpValue.toFixed(3) }}</text>
			</view>
			<view class="info-item">
				<text class="label">过程均值:</text>
				<text class="value">{{ processMean.toFixed(3) }}</text>
			</view>
			<view class="info-item">
				<text class="label">标准差:</text>
				<text class="value">{{ overallStdDev.toFixed(3) }}</text>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		name: 'SpcCPKChart',
		props: {
			data: {
				type: Array,
				required: true
			},
			spec: {
				type: Object,
				default: () => ({
					usl: 1.0,
					lsl: 0.8,
					target: 0.9
				})
			}
		},
		data() {
			return {
				chartWidth: 0,
				chartHeight: 0,
				ctx: null,
				isDragging: false,
				dragStartX: 0,
				dragStartY: 0,
				translateX: 0,
				translateY: 0,
				scale: 1,
				cpkValue: 0,
				cpValue: 0,
				processMean: 0,
				overallStdDev: 0
			}
		},
		computed: {
			// 计算所有样本的集合
			allSamples() {
				return this.data.reduce((acc, group) => [...acc, ...group.samples], []);
			},

			// 计算CPK值
			calculateCpk() {
				if (!this.allSamples.length) return 0;

				const {
					usl,
					lsl
				} = this.spec;
				const mean = this.processMean;
				const stdDev = this.overallStdDev;

				if (stdDev === 0) return 0;

				const cpu = (usl - mean) / (3 * stdDev);
				const cpl = (mean - lsl) / (3 * stdDev);

				return Math.min(cpu, cpl);
			},

			// 计算CP值
			calculateCp() {
				if (!this.allSamples.length) return 0;

				const {
					usl,
					lsl
				} = this.spec;
				const stdDev = this.overallStdDev;

				if (stdDev === 0) return 0;

				return (usl - lsl) / (6 * stdDev);
			},

			// 计算总体均值
			calculateProcessMean() {
				if (!this.allSamples.length) return 0;

				const sum = this.allSamples.reduce((acc, val) => acc + val, 0);
				return sum / this.allSamples.length;
			},

			// 计算总体标准差
			calculateOverallStdDev() {
				if (!this.allSamples.length) return 0;

				const mean = this.processMean;
				const variance = this.allSamples.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0) / this.allSamples
					.length;
				return Math.sqrt(variance);
			}
		},
		watch: {
			// 监听数据变化，重新渲染图表
			data: {
				handler() {
					this.initChart();
				},
				deep: true
			},
			spec: {
				handler() {
					this.initChart();
				},
				deep: true
			}
		},
		mounted() {
			// 获取设备信息，设置图表尺寸
			const res = uni.getSystemInfoSync();
			this.chartWidth = res.windowWidth - 40; // 留出边距
			this.chartHeight = 300;

			// 初始化图表
			this.$nextTick(() => {
				this.initChart();
			});
		},
		methods: {
			// 初始化图表
			initChart() {
				// 获取Canvas上下文
				this.ctx = uni.createCanvasContext('cpkChart', this);

				// 计算统计数据
				this.processMean = this.calculateProcessMean;
				this.overallStdDev = this.calculateOverallStdDev;
				this.cpkValue = this.calculateCpk;
				this.cpValue = this.calculateCp;

				// 绘制图表
				this.drawChart();
			},

			// 绘制整个图表
			drawChart() {
				const {
					ctx,
					chartWidth,
					chartHeight
				} = this;
				const {
					usl,
					lsl,
					target
				} = this.spec;

				// 清除画布
				ctx.clearRect(0, 0, chartWidth, chartHeight);

				// 设置边距
				const margin = {
					top: 20,
					right: 20,
					bottom: 40,
					left: 40
				};
				const plotWidth = chartWidth - margin.left - margin.right;
				const plotHeight = chartHeight - margin.top - margin.bottom;

				// 计算数据范围
				const allValues = [...this.allSamples, usl, lsl, target, this.processMean];
				const minValue = Math.min(...allValues) - 0.05;
				const maxValue = Math.max(...allValues) + 0.05;
				const valueRange = maxValue - minValue;

				// 计算Y轴高度（用于正态分布曲线）
				const maxYValue = 1 / (this.overallStdDev * Math.sqrt(2 * Math.PI)) * 1.2; // 留出一些余量

				// 坐标转换函数
				const xScale = (value) => margin.left + (value - minValue) / valueRange * plotWidth;
				const yScale = (value) => chartHeight - margin.bottom - (value / maxYValue) * plotHeight;

				// 绘制背景网格
				this.drawGrid(ctx, margin, plotWidth, plotHeight);

				// 绘制规格线
				ctx.beginPath();
				ctx.setLineWidth(2);

				// USL线
				ctx.setStrokeStyle('#FF4D4F');
				ctx.moveTo(xScale(usl), margin.top);
				ctx.lineTo(xScale(usl), chartHeight - margin.bottom);
				ctx.stroke();

				// LSL线
				ctx.setStrokeStyle('#FF4D4F');
				ctx.moveTo(xScale(lsl), margin.top);
				ctx.lineTo(xScale(lsl), chartHeight - margin.bottom);
				ctx.stroke();

				// Target线
				ctx.setStrokeStyle('#1890FF');
				ctx.setLineDash([5, 5]);
				ctx.moveTo(xScale(target), margin.top);
				ctx.lineTo(xScale(target), chartHeight - margin.bottom);
				ctx.stroke();
				ctx.setLineDash([]);

				// 绘制规格标签
				ctx.setFontSize(12);
				ctx.setTextAlign('center');
				ctx.setFillStyle('#FF4D4F');
				ctx.fillText(`USL: ${usl}`, xScale(usl), margin.top - 5);
				ctx.fillText(`LSL: ${lsl}`, xScale(lsl), margin.top - 5);

				ctx.setFillStyle('#1890FF');
				ctx.fillText(`Target: ${target}`, xScale(target), margin.top - 5);

				// 绘制样本点
				const groupWidth = plotWidth / this.data.length;
				this.data.forEach((group, index) => {
					const groupX = margin.left + index * groupWidth + groupWidth / 2;

					group.samples.forEach(sample => {
						const x = groupX;
						const y = yScale(sample);

						ctx.beginPath();
						ctx.arc(x, y, 3, 0, 2 * Math.PI);

						// 判断样本是否超出规格
						if (sample > usl || sample < lsl) {
							ctx.setFillStyle('#FF4D4F'); // 红色表示超出规格
						} else {
							ctx.setFillStyle('#13C2C2'); // 青色表示在规格内
						}

						ctx.fill();
					});
				});

				// 绘制正态分布曲线
				ctx.beginPath();
				ctx.setStrokeStyle('#722ED1');
				ctx.setLineWidth(2);

				const curvePoints = 100;
				for (let i = 0; i <= curvePoints; i++) {
					const xValue = minValue + (i / curvePoints) * valueRange;
					const yValue = this.calculateNormalDistribution(xValue, this.processMean, this.overallStdDev);

					const x = xScale(xValue);
					const y = yScale(yValue);

					if (i === 0) {
						ctx.moveTo(x, y);
					} else {
						ctx.lineTo(x, y);
					}
				}

				ctx.stroke();

				// 绘制均值线
				ctx.beginPath();
				ctx.setStrokeStyle('#FAAD14');
				ctx.setLineWidth(2);
				ctx.moveTo(xScale(this.processMean), margin.top);
				ctx.lineTo(xScale(this.processMean), chartHeight - margin.bottom);
				ctx.stroke();

				// 绘制均值标签
				ctx.setFontSize(12);
				ctx.setTextAlign('center');
				ctx.setFillStyle('#FAAD14');
				ctx.fillText(`Mean: ${this.processMean.toFixed(3)}`, xScale(this.processMean), chartHeight - margin
					.bottom + 15);

				// 绘制X轴和标签
				ctx.beginPath();
				ctx.setStrokeStyle('#000');
				ctx.setLineWidth(1);
				ctx.moveTo(margin.left, chartHeight - margin.bottom);
				ctx.lineTo(chartWidth - margin.right, chartHeight - margin.bottom);
				ctx.stroke();

				// 绘制X轴刻度和标签
				const numTicks = 5;
				for (let i = 0; i <= numTicks; i++) {
					const x = margin.left + (i / numTicks) * plotWidth;
					const value = minValue + (i / numTicks) * valueRange;

					ctx.beginPath();
					ctx.moveTo(x, chartHeight - margin.bottom);
					ctx.lineTo(x, chartHeight - margin.bottom + 5);
					ctx.stroke();

					ctx.setFontSize(10);
					ctx.setTextAlign('center');
					ctx.setFillStyle('#000');
					ctx.fillText(value.toFixed(3), x, chartHeight - margin.bottom + 20);
				}

				// 绘制CPK值标签
				ctx.setFontSize(14);
				ctx.setTextAlign('left');
				ctx.setFillStyle('#000');
				ctx.fillText(`CPK: ${this.cpkValue.toFixed(3)}`, margin.left, margin.top - 5);

				// 绘制CP值标签
				ctx.fillText(`CP: ${this.cpValue.toFixed(3)}`, margin.left + 100, margin.top - 5);

				// 绘制图例
				this.drawLegend(ctx, margin, plotWidth);

				// 执行绘制
				ctx.draw();
			},

			// 计算正态分布值
			calculateNormalDistribution(x, mean, stdDev) {
				return (1 / (stdDev * Math.sqrt(2 * Math.PI))) *
					Math.exp(-0.5 * Math.pow((x - mean) / stdDev, 2));
			},

			// 绘制网格
			drawGrid(ctx, margin, plotWidth, plotHeight) {
				ctx.beginPath();
				ctx.setStrokeStyle('#E5E5E5');
				ctx.setLineWidth(1);

				// 水平网格线
				const numHorizontalLines = 4;
				for (let i = 0; i <= numHorizontalLines; i++) {
					const y = margin.top + (i / numHorizontalLines) * plotHeight;

					ctx.moveTo(margin.left, y);
					ctx.lineTo(margin.left + plotWidth, y);
				}

				// 垂直网格线
				const numVerticalLines = 4;
				for (let i = 0; i <= numVerticalLines; i++) {
					const x = margin.left + (i / numVerticalLines) * plotWidth;

					ctx.moveTo(x, margin.top);
					ctx.lineTo(x, margin.top + plotHeight);
				}

				ctx.stroke();
			},

			// 绘制图例
			drawLegend(ctx, margin, plotWidth) {
				const legendItems = [{
						text: 'USL/LSL',
						color: '#FF4D4F'
					},
					{
						text: 'Target',
						color: '#1890FF'
					},
					{
						text: 'Process Mean',
						color: '#FAAD14'
					},
					{
						text: 'Normal Distribution',
						color: '#722ED1'
					},
					{
						text: 'Samples',
						color: '#13C2C2'
					}
				];

				const legendX = margin.left + plotWidth - 120;
				const legendY = margin.top;
				const itemHeight = 20;

				legendItems.forEach((item, index) => {
					const y = legendY + index * itemHeight;

					// 绘制颜色方块
					ctx.beginPath();
					ctx.setFillStyle(item.color);
					ctx.fillRect(legendX, y, 10, 10);

					// 绘制文字
					ctx.setFontSize(10);
					ctx.setTextAlign('left');
					ctx.setFillStyle('#000');
					ctx.fillText(item.text, legendX + 15, y + 9);
				});
			},

			// 触摸事件处理
			handleTouchStart(e) {
				this.isDragging = true;
				this.dragStartX = e.touches[0].x;
				this.dragStartY = e.touches[0].y;
			},

			handleTouchMove(e) {
				if (!this.isDragging) return;

				const currentX = e.touches[0].x;
				const currentY = e.touches[0].y;
				const deltaX = currentX - this.dragStartX;
				const deltaY = currentY - this.dragStartY;

				this.dragStartX = currentX;
				this.dragStartY = currentY;

				// 更新平移值
				this.translateX += deltaX;
				this.translateY += deltaY;

				// 重新绘制图表
				this.drawChart();
			},

			handleTouchEnd() {
				this.isDragging = false;
			}
		}
	}
</script>

<style scoped>
	.cpk-chart-container {
		width: 100%;
		padding: 10px;
		background-color: #fff;
		border-radius: 8px;
		box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
	}

	.cpk-chart {
		width: 100%;
		height: 300px;
	}

	.chart-info {
		display: flex;
		flex-wrap: wrap;
		padding: 10px 0;
	}

	.info-item {
		width: 50%;
		display: flex;
		align-items: center;
		margin-bottom: 5px;
	}

	.label {
		color: #8c8c8c;
		font-size: 12px;
		width: 80px;
	}

	.value {
		color: #1f1f1f;
		font-size: 14px;
		font-weight: 500;
	}
</style>